#include <vector>
#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include <iostream>
#include "acl/acl.h"
#include "model_desc_internal.h"
#include "gmock_executor/ge_executor_stub.h"
#include "stub/acl_ge_stub.h"
#include "external/ge/ge_error_codes.h"
#include <stdio.h>
#include <cstring>

#define protected public
#define private public

#undef private
#undef protected

using namespace std;
using namespace testing;
using ::testing::Return;
using ::testing::Eq;
using ::testing::NotNull;
using ::testing::Invoke;
using ::testing::_;
extern bool aclInitFlag;
extern bool aclDeInitFlag;
class AclTest : public testing::Test {
protected:

  void SetUp(){}

  void TearDown(){}
};

TEST_F(AclTest, TestAclaclmdlLoadWithConfigExe) {
  uint32_t modelId;
  aclmdlConfigHandle handle;
  EXPECT_EQ(aclmdlLoadWithConfig(&handle, &modelId), ACL_ERROR_INVALID_PARAM);
  EXPECT_EQ(aclmdlLoadWithConfig(nullptr, &modelId), ACL_ERROR_INVALID_PARAM);
  EXPECT_EQ(aclmdlLoadWithConfig(&handle, nullptr), ACL_ERROR_INVALID_PARAM);
}

TEST_F(AclTest, DataSet) {
  aclmdlDataset *dataSet = aclmdlCreateDataset();
  EXPECT_NE(dataSet, nullptr);
  aclError ret = aclmdlAddDatasetBuffer(dataSet, nullptr);
  EXPECT_NE(ret, ACL_SUCCESS);
  ret = aclmdlAddDatasetBuffer(dataSet, (aclDataBuffer *)0x01);
  EXPECT_EQ(ret, ACL_SUCCESS);
  size_t size = aclmdlGetDatasetNumBuffers(nullptr);
  EXPECT_EQ(size, 0);
  size = aclmdlGetDatasetNumBuffers(dataSet);
  EXPECT_EQ(size, 1);
  aclDataBuffer *dataBuffer = aclmdlGetDatasetBuffer(dataSet, 1);
  EXPECT_EQ(dataBuffer, nullptr);
  dataBuffer = aclmdlGetDatasetBuffer(dataSet, 0);
  EXPECT_NE(dataBuffer, nullptr);
  ret = aclmdlAddDatasetBuffer(nullptr, nullptr);
  EXPECT_NE(ret, ACL_SUCCESS);
  ret = aclmdlDestroyDataset(nullptr);
  EXPECT_NE(ret, ACL_SUCCESS);
  ret = aclmdlDestroyDataset(dataSet);
  EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclmdlQuerySize) {
  const char *fileName = "/home";
  size_t memSize;
  size_t weightSize;

  aclError ret = aclmdlQuerySize(nullptr, nullptr, nullptr);
  EXPECT_NE(ret, ACL_SUCCESS);
  EXPECT_CALL(GeExecutorStubMock::GetInstance(), GetMemAndWeightSize(_,_,_)).Times(1).WillOnce(Return(SUCCESS));
  ret = aclmdlQuerySize(fileName, &memSize, &weightSize);
  EXPECT_EQ(ret, ACL_SUCCESS);

  EXPECT_CALL(GeExecutorStubMock::GetInstance(), GetMemAndWeightSize(_,_,_)).Times(1).WillOnce(Return(ACL_ERROR_INVALID_PARAM));
  ret = aclmdlQuerySize(fileName, &memSize, &weightSize);
  EXPECT_NE(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclmdlExecuteAsyncV2) {
  aclmdlDataset *dataset = aclmdlCreateDataset();
  EXPECT_NE(dataset, nullptr);

  aclDataBuffer *dataBuffer = (aclDataBuffer *)malloc(100);
  aclError ret = aclmdlAddDatasetBuffer(dataset, dataBuffer);
  EXPECT_EQ(ret, ACL_SUCCESS);
  aclmdlExecConfigHandle handle;
  EXPECT_CALL(GeExecutorStubMock::GetInstance(), ExecModel(_,_,_,_,_)).Times(1).WillOnce(Return(SUCCESS));
  ret = aclmdlExecuteAsyncV2(1, dataset, dataset, nullptr, &handle);
  EXPECT_EQ(ret, ACL_SUCCESS);

  handle.workPtr = NULL;
  ret = aclmdlExecuteAsyncV2(1, dataset, dataset, nullptr, &handle);
  EXPECT_NE(ret, ACL_SUCCESS);

  aclrtStream stream = (void *)0x0010;
  ret = aclmdlExecuteAsyncV2(1, dataset, dataset, stream, &handle);
  EXPECT_NE(ret, ACL_SUCCESS);

  ret = aclmdlExecuteAsyncV2(1, nullptr, nullptr, nullptr, nullptr);
  EXPECT_NE(ret, ACL_SUCCESS);

  free(dataBuffer);
  ret = aclmdlDestroyDataset(dataset);
  EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclmdlExecuteV2) {
  aclmdlDataset *dataset = aclmdlCreateDataset();
  EXPECT_NE(dataset, nullptr);

  aclDataBuffer *dataBuffer = (aclDataBuffer *)malloc(100);
  aclError ret = aclmdlAddDatasetBuffer(dataset, dataBuffer);
  EXPECT_EQ(ret, ACL_SUCCESS);
  aclmdlExecConfigHandle *handle = aclmdlCreateExecConfigHandle();
  void *p = (void *)0x0001;
  size_t size = 100UL;
  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_WORK_ADDR_PTR, &p, 0);
  EXPECT_NE(ret, ACL_SUCCESS);
  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_WORK_ADDR_PTR, &p, sizeof(p));
  EXPECT_EQ(ret, ACL_SUCCESS);
  EXPECT_EQ(handle->workPtr, p);

  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_WORK_SIZET, &size, 0);
  EXPECT_NE(ret, ACL_SUCCESS);
  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_WORK_SIZET, &size, sizeof(size));
  EXPECT_EQ(ret, ACL_SUCCESS);

  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_MPAIMID_SIZET, &size, 0);
  EXPECT_NE(ret, ACL_SUCCESS);
  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_MPAIMID_SIZET, &size, sizeof(size));
  EXPECT_EQ(ret, ACL_SUCCESS);

  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_AICQOS_SIZET, &size, 0);
  EXPECT_NE(ret, ACL_SUCCESS);
  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_AICQOS_SIZET, &size, sizeof(size));
  EXPECT_EQ(ret, ACL_SUCCESS);

  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_AICOST_SIZET, &size, 0);
  EXPECT_NE(ret, ACL_SUCCESS);
  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_AICOST_SIZET, &size, sizeof(size));
  EXPECT_EQ(ret, ACL_SUCCESS);

  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_MEC_TIMETHR_SIZET, &size, 0);
  EXPECT_NE(ret, ACL_SUCCESS);
  ret = aclmdlSetExecConfigOpt(handle, ACL_MDL_MEC_TIMETHR_SIZET, &size, sizeof(size));
  EXPECT_EQ(ret, ACL_SUCCESS);

  EXPECT_CALL(GeExecutorStubMock::GetInstance(), ExecModel(_,_,_,_,_)).Times(1).WillOnce(Return(SUCCESS));
  ret = aclmdlExecuteV2(1, dataset, dataset, nullptr, handle);
  EXPECT_EQ(ret, ACL_SUCCESS);

  ret = aclmdlExecuteV2(1, nullptr, nullptr, nullptr, nullptr);
  EXPECT_NE(ret, ACL_SUCCESS);

  free(dataBuffer);
  ret = aclmdlDestroyDataset(dataset);
  EXPECT_EQ(ret, ACL_SUCCESS);
  aclmdlDestroyExecConfigHandle(handle);
}
TEST_F(AclTest, aclmdlLoadWithConfigErr) {
  aclmdlConfigHandle *handle = aclmdlCreateConfigHandle();
  size_t type = ACL_MDL_LOAD_FROM_FILE;
  aclError ret = aclmdlSetConfigOpt(handle, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  EXPECT_EQ(ret, ACL_SUCCESS);
  uint32_t modelId;
  ret = aclmdlLoadWithConfig(handle, &modelId);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  aclmdlDestroyConfigHandle(handle);

  aclmdlConfigHandle *handle2 = aclmdlCreateConfigHandle();
  type = ACL_MDL_LOAD_FROM_MEM;
  ret = aclmdlSetConfigOpt(handle2, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  EXPECT_EQ(ret, ACL_SUCCESS);
  ret = aclmdlLoadWithConfig(handle2, &modelId);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);

  void *p = (void *)0x0004;
  ret = aclmdlSetConfigOpt(handle2, ACL_MDL_MEM_ADDR_PTR, &p, sizeof(p));
  EXPECT_EQ(ret, ACL_SUCCESS);
  ret = aclmdlLoadWithConfig(handle2, &modelId);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  aclmdlDestroyConfigHandle(handle2);

  aclmdlConfigHandle *handle3 = aclmdlCreateConfigHandle();
  type = ACL_MDL_LOAD_FROM_MEM;
  ret = aclmdlSetConfigOpt(handle3, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  EXPECT_EQ(ret, ACL_SUCCESS);
  ret = aclmdlSetConfigOpt(handle3, ACL_MDL_MEM_ADDR_PTR, &p, sizeof(p));
  EXPECT_EQ(ret, ACL_SUCCESS);
  size_t modelSize1 = 0;
  ret = aclmdlSetConfigOpt(handle3, ACL_MDL_MEM_SIZET, &modelSize1, sizeof(modelSize1));
  ret = aclmdlLoadWithConfig(handle3, &modelId);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  aclmdlDestroyConfigHandle(handle3);
}

TEST_F(AclTest, aclmdlLoadWithConfig) {
  aclmdlConfigHandle *handle = aclmdlCreateConfigHandle();
  void *p = (void *)0x0002;
  aclError ret = aclmdlSetConfigOpt(handle, ACL_MDL_MEM_ADDR_PTR, &p, sizeof(p));
  EXPECT_EQ(ret, ACL_SUCCESS);
  size_t type = ACL_MDL_LOAD_FROM_FILE_WITH_Q;
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);

  type = ACL_MDL_LOAD_FROM_MEM_WITH_MEM;
  aclmdlSetConfigOpt(handle, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));

  size_t modelSize1 = 1;
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_MEM_SIZET, &modelSize1, 0);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);

  ret = aclmdlSetConfigOpt(handle, ACL_MDL_MEM_SIZET, &modelSize1, sizeof(modelSize1));
  EXPECT_EQ(ret, ACL_SUCCESS);
  const char *path = "/home";
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_PATH_PTR, &path, 0);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_PATH_PTR, &path, sizeof(path));
  EXPECT_EQ(ret, ACL_SUCCESS);
  EXPECT_EQ(strcmp(handle->loadPath, path), 0);

  ret = aclmdlSetConfigOpt(handle, ACL_MDL_WORKSPACE_ADDR_PTR, &p, 0);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_WORKSPACE_ADDR_PTR, &p, sizeof(p));
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_WORKSPACE_SIZET, &modelSize1, 0);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_WORKSPACE_SIZET, &modelSize1, sizeof(modelSize1));
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_WEIGHT_ADDR_PTR, &p, 0);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_WEIGHT_ADDR_PTR, &p, sizeof(p));
  EXPECT_EQ(ret, ACL_SUCCESS);
  EXPECT_EQ(handle->weightPtr, p);

  ret = aclmdlSetConfigOpt(handle, ACL_MDL_WEIGHT_SIZET, &modelSize1, 0);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  ret = aclmdlSetConfigOpt(handle, ACL_MDL_WEIGHT_SIZET, &modelSize1, sizeof(modelSize1));
  EXPECT_EQ(ret, ACL_SUCCESS);

  uint32_t modelId;
  EXPECT_CALL(GeExecutorStubMock::GetInstance(), LoadModelFromData(_,_,_,_)).Times(1).WillOnce(Return(SUCCESS));
  ret = aclmdlLoadWithConfig(handle, &modelId);
  EXPECT_EQ(ret, ACL_SUCCESS);

  type = ACL_MDL_LOAD_FROM_MEM;
  EXPECT_CALL(GeExecutorStubMock::GetInstance(), LoadModelFromData(_,_,_,_)).Times(1).WillOnce(Return(SUCCESS));
  aclmdlSetConfigOpt(handle, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  ret = aclmdlLoadWithConfig(handle, &modelId);
  EXPECT_EQ(ret, ACL_SUCCESS);

  EXPECT_CALL(GeExecutorStubMock::GetInstance(), LoadModelFromData(_,_,_,_)).Times(1).WillOnce(Return(ACL_ERROR_GE_PARAM_INVALID));
  aclmdlSetConfigOpt(handle, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  ret = aclmdlLoadWithConfig(handle, &modelId);
  EXPECT_NE(ret, ACL_SUCCESS);


  type = ACL_MDL_LOAD_FROM_FILE_WITH_MEM;
  EXPECT_CALL(MockFunctionTest::aclStubInstance(), LoadDataFromFile(_,_)).Times(1).WillOnce(Return(ACL_ERROR_GE_PARAM_INVALID));
  aclmdlSetConfigOpt(handle, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  ret = aclmdlLoadWithConfig(handle, &modelId);
  EXPECT_NE(ret, ACL_SUCCESS);

  EXPECT_CALL(MockFunctionTest::aclStubInstance(), LoadDataFromFile(_,_)).Times(1).WillOnce(Return(SUCCESS));
  EXPECT_CALL(GeExecutorStubMock::GetInstance(), LoadModelFromData(_,_,_,_)).Times(1).WillOnce(Return(ACL_ERROR_GE_PARAM_INVALID));
  aclmdlSetConfigOpt(handle, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  ret = aclmdlLoadWithConfig(handle, &modelId);
  EXPECT_NE(ret, ACL_SUCCESS);

  EXPECT_CALL(MockFunctionTest::aclStubInstance(), LoadDataFromFile(_,_)).Times(1).WillOnce(Return(SUCCESS));
  EXPECT_CALL(GeExecutorStubMock::GetInstance(), LoadModelFromData(_,_,_,_)).Times(1).WillOnce(Return(SUCCESS));
  aclmdlSetConfigOpt(handle, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  ret = aclmdlLoadWithConfig(handle, &modelId);
  EXPECT_EQ(ret, ACL_SUCCESS);

  type = ACL_MDL_LOAD_FROM_FILE;
  EXPECT_CALL(MockFunctionTest::aclStubInstance(), LoadDataFromFile(_,_)).Times(1).WillOnce(Return(SUCCESS));
  EXPECT_CALL(GeExecutorStubMock::GetInstance(), LoadModelFromData(_,_,_,_)).Times(1).WillOnce(Return(SUCCESS));
  aclmdlSetConfigOpt(handle, ACL_MDL_LOAD_TYPE_SIZET, &type, sizeof(type));
  ret = aclmdlLoadWithConfig(handle, &modelId);
  EXPECT_EQ(ret, ACL_SUCCESS);

  aclmdlDestroyConfigHandle(handle);
}

TEST_F(AclTest, aclmdlUnload) {
  EXPECT_CALL(GeExecutorStubMock::GetInstance(), UnloadModel(_)).Times(1).WillOnce(Return(SUCCESS));
  aclError ret = aclmdlUnload(0);
  EXPECT_EQ(ret, ACL_SUCCESS);

  EXPECT_CALL(GeExecutorStubMock::GetInstance(), UnloadModel(_)).Times(1).WillOnce(Return(ACL_ERROR_GE_PARAM_INVALID));
  ret = aclmdlUnload(0);
  EXPECT_NE(ret, ACL_SUCCESS);
}

TEST_F(AclTest, DataBuffer) {
  aclmdlDataset *dataset = aclmdlCreateDataset();
  EXPECT_NE(dataset, nullptr);

  aclError ret = aclmdlAddDatasetBuffer(dataset, nullptr);
  EXPECT_NE(ret, ACL_SUCCESS);

  ret = aclmdlAddDatasetBuffer(dataset, (aclDataBuffer *)0x01);
  EXPECT_EQ(ret, ACL_SUCCESS);

  size_t size = aclmdlGetDatasetNumBuffers(nullptr);
  EXPECT_EQ(size, 0);

  size = aclmdlGetDatasetNumBuffers(dataset);
  EXPECT_EQ(size, 1);

  aclDataBuffer *dataBuffer = aclmdlGetDatasetBuffer(dataset, 1);
  EXPECT_EQ(dataBuffer, nullptr);

  dataBuffer = aclmdlGetDatasetBuffer(dataset, 0);
  EXPECT_NE(dataBuffer, nullptr);

  ret = aclmdlAddDatasetBuffer(nullptr, nullptr);
  EXPECT_NE(ret, ACL_SUCCESS);

  ret = aclmdlDestroyDataset(nullptr);
  EXPECT_NE(ret, ACL_SUCCESS);

  ret = aclmdlDestroyDataset(dataset);
  EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclGetDataBufferSizeV2) {
  aclDataBuffer *buffer = aclCreateDataBuffer((void*)0x1, 1);
  EXPECT_EQ(aclGetDataBufferSizeV2(nullptr), 0);
  EXPECT_EQ(aclGetDataBufferSizeV2(buffer), 1);
  aclDestroyDataBuffer(buffer);
}

TEST_F(AclTest, aclGetDataBufferAddr) {
  aclDataBuffer *dataBuffer = nullptr;
  EXPECT_EQ(aclGetDataBufferAddr(dataBuffer), nullptr);
  dataBuffer = aclCreateDataBuffer((void *)0x1, 1);
  EXPECT_NE(aclGetDataBufferAddr(dataBuffer), nullptr);
  aclDestroyDataBuffer(dataBuffer);
}